/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						 adventure_path_finder.h

	$Header: /heroes4/adventure_path_finder.h $

	$NoKeywords: $

 ************************************************************************/

#if !defined( ADVENTURE_PATH_FINDER_H_INCLUDED )
#define ADVENTURE_PATH_FINDER_H_INCLUDED

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <queue>
#include <limits>

#include "adventure_path.h"
#include "adventure_enemy_marker.h"
#include "counted_ptr.h"
#include "creature_array.h"
#include "danger_map.h"
#include "handler.h"
#include "isometric_map.h"
#include "path_point_array.h"

struct t_path_step;

class t_compare_adjusted_move_cost
{
public:
	bool operator()( t_adventure_path_point const& left, 
		             t_adventure_path_point const& right ) const
	{
		return left.adjusted_move_cost > right.adjusted_move_cost;
	}
};

class t_adventure_path_queue : public std::priority_queue< t_adventure_path_point,
														   std::vector<t_adventure_path_point>, 
														   t_compare_adjusted_move_cost >
{
};

typedef std::list<t_adv_map_point> t_visited_adv_points;

// ---------------------------------------------------------------
// class to find paths for adventure map
// ---------------------------------------------------------------
class t_adventure_path_finder : public t_adventure_enemy_marker
{
public:
	// First parameter is point. Next parameter should be set to true to stop search
	typedef t_handler_2< t_adventure_path_point const &, bool & > t_search_handler;

	t_adventure_path_finder( t_adventure_map& map );

	bool							can_summon_boat();
	t_adventure_path_data const&	get_data( t_adv_map_point const& point );
	t_danger_map_ptr				get_danger_map() const;
	bool							get_path( t_adv_map_point	 destination, 
											  t_adventure_path&  path, 
											  unsigned int		 move_points = std::numeric_limits< unsigned int>::max() );
	void							handler_based_search( t_search_handler handler );
	void							initialize();
	bool							push( t_adv_map_point const&        point,
										  t_adventure_path_point const& prev_point,
										  unsigned int					move_cost,
										  unsigned int					additional_adjusted_move_cost = 0, 
										  float                         barrier_value = 0.0,
										  t_army_path_state			    new_path_state = k_army_path_state_previous );
	void							seed_position( t_visited_adv_points&   visited_points, 
												   unsigned int			move_points );
	void							set_danger_map( t_danger_map_ptr danger_ptr );
protected:
	bool				check_danger( t_path_step& step ) const;
	t_adventure_object* check_trigger( t_path_step& step ) const;
	bool				check_water( t_path_step& step );
	bool				enter_blocked_tile( t_path_step& step );
	bool				push( t_path_step& step );
	void				search_to( t_adv_map_point const*		point,	// If this value is NULL the search graphs all points without stopping at a destination
								   unsigned int				move_points,
								   t_search_handler			handler ); // Maximum move points to expend
	bool				validate_danger( t_adventure_path_point const& point );
	bool				validate_point( t_adventure_path_point const &point );
	bool				validate_water_step( t_path_step const& step ) const;

	bool								m_can_summon_boat;
	t_danger_map_ptr					m_danger_map_ptr;
	int									m_movement[2];
	t_adventure_path_queue				m_open_points;
	int									m_patrol_array_size;
	int									m_patrol_distance;
	t_adv_map_point						m_starting_point;
	bool								m_summon_boat_checked;
	t_visited_adv_points*				m_visited_points;
};

inline t_danger_map_ptr t_adventure_path_finder::get_danger_map() const
{
	return m_danger_map_ptr;
}

inline void t_adventure_path_finder::set_danger_map( t_danger_map_ptr danger_ptr )
{
	m_danger_map_ptr = danger_ptr;
}

t_army* find_enemy( t_adventure_map&				map,
			        t_adventure_enemy_marker const&	path_finder, 
					t_adv_map_point					point, 
					t_creature_array const&			army,
					t_direction*					direction = 0 );
t_army* find_restrictive_enemy( t_adventure_map&				map, 
						        t_adventure_enemy_marker const&	path_finder, 
								t_adv_map_point					point, 
								t_creature_array const&			army,
								t_direction*					direction = 0 );

typedef t_handler_1< t_adv_map_point const & > t_place_army_handler;

bool start_object_adjacent_pathfind( t_adventure_path_finder & pathfinder, 
									 t_adventure_object const & object,
									 t_creature_array & army,
									 t_path_search_type search_type,
									 t_place_army_handler place_army_handler );

#endif // ADVENTURE_PATH_FINDER_H_INCLUDED